package com.rrkd.handler;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.HashedWheelTimer;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.rrkd.model.RequestFile;
import com.rrkd.model.ResponseFile;
import com.rrkd.server.StatusInterface;
import com.rrkd.util.CRC;
import com.rrkd.util.FileTransferProperties;
import com.rrkd.util.FileUtils;
import com.rrkd.util.GzipUtils;
import com.rrkd.util.MyException;
import com.rrkd.util.SM3;
import com.rrkd.util.SM4Utils;
import com.rrkd.util.Status;

public class FileTransferServerHandler extends ChannelInboundHandlerAdapter   {

	private static final Logger log = LoggerFactory
			.getLogger(FileTransferServerHandler.class);

	private volatile  int byteRead;
	private volatile  long start = 0;
	private  String filepath = "";
	/**
	 * 文件默认存储地址
	 */
	private  String file_dir = FileTransferProperties.getString(
			"file_write_path", "/");

	private  RandomAccessFile randomAccessFile;
	private  File file;
	private long fileSize = -1;
	
	private  String sm3 = "";

	private  String SM3Code = "";
	private  String crc = "";
	static String newfile_dir = "";
	public FileTransferServerHandler(){
		
	}

	public  void Write(RequestFile ef,ChannelHandlerContext ctx) throws IOException {
		
		byte[] bytes = ef.getBytes();;
		
		String upload_status = ef.getUpload_status(); // 上传文件的方式
		
		byteRead = ef.getEndPos();
		SM3Code = ef.getSM3(); // 文件的SM3的值
		crc = ef.getCrc(); // 文件的差错性校验码

		if(start==0){
			
		
		if (upload_status != null && upload_status.equals("dir")) { //传输的文件类型为文件夹
			newfile_dir = ef.getUploadDestPath() + File.separator + ef.getParent();
			file = new File(newfile_dir);
			fileSize = ef.getLocalfile_size();
		} else if (ef.getFile_type() != null && ef.getFile_type().equals("emptydir")) {
			
			newfile_dir = ef.getUploadDestPath() + File.separator + ef.getParent(); //传输空文件夹，直接返回给客户端
			try {
				file = new File(newfile_dir);
				if (!file.exists()) {
					file.mkdirs();
				}
			} catch (Exception e) {
				log.info(e.toString());
				file=new File(file_dir); //如果选择的路径不存在，则存放到默认的文件目录中
			}
			
			ResponseFile responseFile = new ResponseFile(start, sm3,getFilePath(),"空文件夹传输完成");
			ctx.writeAndFlush(responseFile);
			return;
		} else {
			
			newfile_dir = ef.getUploadDestPath();//传输的类型为文件
			file = new File(newfile_dir);
			fileSize = ef.getLocalfile_size();
		}

			if (!file.exists()) {
				file.mkdirs();
			}
			filepath = newfile_dir + File.separator + ef.getFile_name()
					+ ef.getFile_type();
			file = new File(filepath);
		}	

		
	if (upload_status != null
			&& upload_status.equals(StatusInterface.UPLOAD_POINT)) {  // 进行断点续传
		
		//WriteToServerByPoint(ef);
		start=ef.getStarPos();//断点的起始位置
		Writetoserver(file, bytes);
		Response(ctx);// 返回客户端信息
		
	}else{
	
		if(ef.isSm4()){
			bytes=SM4Utils.decryptData_CBC(new String(bytes,"GBK")).getBytes("GBK");
		}else if(ef.isAttachment()){
			bytes=GzipUtils.ungzip(bytes);
		}
	
		Writetoserver(file, bytes);
		
		Response(ctx);// 返回客户端信息
	}
		}	
	


	/**
	 * 文件的断点续传
	 *  为了代码的简洁，断点续传的方法代码采用的是文件上传的代码
	 * @param ef
	 */
//	public  void WriteToServerByPoint(RequestFile ef) {
//
//		long localreadbytes = 0l;
//
//		try {
//
//			int c;
//			OutputStream output = new FileOutputStream(file);
//			byte bytess[] = new byte[1024];
//			randomAccessFile = new RandomAccessFile(ef.getFile(), "rw");
//			randomAccessFile.seek(ef.getStarPos());
//			while ((c = randomAccessFile.read(bytess)) != -1) {
//				localreadbytes += c;
//				output.write(bytess, 0, c);
//				if (localreadbytes % 4096 == 0) {
//					output.flush();
//				}
//
//			}
//			output.flush();
//			output.close();
//		} catch (FileNotFoundException e) {
//			log.info(e.toString());
//		} catch (IOException e) {
//			log.info(e.toString());
//		} finally {
//			try {
//				if(randomAccessFile!=null){
//					randomAccessFile.close();
//				}
//
//			} catch (IOException e) {
//
//				log.info(e.toString());
//			}
//		}
//
//	}

	/**
	 * 写入文件
	 * 
	 * @param file
	 * @param bytes
	 *
	 * @throws Exception
	 */
	public  void Writetoserver(File file, byte[] bytes) {
	
		
		try {

			randomAccessFile = new RandomAccessFile(file, "rw");
			randomAccessFile.seek(start);
			randomAccessFile.write(bytes, 0, byteRead);
			start = start + byteRead;
	

		} catch (FileNotFoundException e) {

			log.info(e.toString());
		} catch (IOException e) {

			log.info(e.toString());
		} catch (Exception e) {
			
			log.info(e.toString());
		}finally{
			try {
				if(randomAccessFile!=null)
				randomAccessFile.close();
			} catch (IOException e) {

				log.info(e.toString());
			}
		}
		
	}

	public  void Response(ChannelHandlerContext ctx) throws IOException {

		if (byteRead > 0 && (start < fileSize && fileSize != -1)) {
			
			ResponseFile responseFile = new ResponseFile(start,sm3,(start*100)/fileSize);
			ctx.writeAndFlush(responseFile);
		} else {
			String checkResult=FileUtils.CheckSM3andCrc(file,SM3Code,crc);//验证文件的完整性和差错性
			ResponseFile responseFile = new ResponseFile(start,sm3,getFilePath(), checkResult);
			ctx.writeAndFlush(responseFile);
			
			start=0;
			if(randomAccessFile!=null)
			randomAccessFile.close();
		}

	}

	@Override
	public  void channelRead(ChannelHandlerContext ctx, Object msg)
			throws MyException {

		if (msg instanceof RequestFile) {
			
			RequestFile ef=(RequestFile) msg;;

			try {
				Write(ef,ctx);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			

		}

	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
		cause.printStackTrace();

		// 当连接断开的时候 关闭未关闭的文件流
		if (randomAccessFile != null) {
			try {
				randomAccessFile.close();
			} catch (IOException e) {
				log.info(e.toString());
				
			}
		}
		ctx.close();
	}

	/**
	 * 获取 文件路径
	 * 
	 * @return
	 */
	private  String getFilePath() {
		if (file != null)
			return FileTransferProperties.getString("download_root_path") + "/"
					+ file.getName();
		else
			return null;
	}

	public static void main(String[] args) {
		String cont=SM4Utils.decryptData_CBC(FileUtils.readString3(new File("E://nettydemo//test//test11secret.txt")));
		try {
			FileWriter fw=new FileWriter(new File("E://nettydemo//test//test11.txt"));
			fw.write(cont);
		} catch (IOException e) {
			
			e.printStackTrace();
		}
	}
	


}
